package com.arpa.wms.service.impl;

import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.cache.BatchRuleCache;
import com.arpa.wms.cache.GoodsCache;
import com.arpa.wms.cache.LocationCache;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.dto.DeliveryDistributionDTO;
import com.arpa.wms.domain.dto.PickItemCancelQuantityDto;
import com.arpa.wms.domain.dto.PickingRegisterDTO;
import com.arpa.wms.domain.entity.*;
import com.arpa.wms.domain.enums.PickingRegisterStatusEnum;
import com.arpa.wms.domain.enums.PickingStatusEnum;
import com.arpa.wms.domain.vo.DeliveryDistributionVO;
import com.arpa.wms.domain.vo.PdaPickingRegisterVO;
import com.arpa.wms.domain.vo.PickingRegisterVO;
import com.arpa.wms.mapper.PickingRegisterMapper;
import com.arpa.wms.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.testng.collections.Lists;
import org.testng.collections.Maps;

import java.math.BigDecimal;
import java.sql.Struct;
import java.util.*;
import java.util.stream.Collectors;

import static com.arpa.wms.domain.consts.CommonConst.LOT_NUMBER;

/**
 * <p>
 * 拣货明细确认单 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-10-22
 */
@Service
public class PickingRegisterServiceImpl extends ServiceImpl<PickingRegisterMapper, PickingRegister> implements IPickingRegisterService {

    @Autowired
    private PartyCache partyCache;
    @Autowired
    private GoodsCache goodsCache;
    @Autowired
    private BatchRuleCache batchRuleCache;
    @Autowired
    @Lazy
    private IPickingItemService pickingItemService;
    @Autowired
    private IGoodsPnService goodsPnService;
    @Autowired
    @Lazy
    private IDeliveryDistributionService deliveryDistributionService;
    @Autowired
    private LocationCache locationCache;
    @Autowired
    @Lazy
    private IWmsTaskService wmsTaskService;
    /**
     * 保存
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public boolean save(PickingRegister entity) {
        if(StringUtils.isBlank(entity.getCode())){
            entity.setCode(IdUtil.simpleUUID());
        }
        if(StringUtils.isBlank(entity.getCreatedBy())){
            entity.setCreatedBy(UserUtil.getCode());
            entity.setCreatedName(partyCache.translate(UserUtil.getCode()));
        }
        return super.save(entity);
    }

    /**
     * 根据code更新实体
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public int updateByCode(PickingRegister entity) {
        if(StringUtils.isBlank(entity.getModifiedBy())){
            entity.setModifiedBy(UserUtil.getCode());
            entity.setModifiedName(partyCache.translate(UserUtil.getCode()));
        }
        return baseMapper.update(entity,new QueryWrapper<PickingRegister>().lambda().eq(PickingRegister::getCode,entity.getCode()));
    }

    /**
     * 查询列表
     * @param pickingRegisterDTO
     * @return
     */
    @Override
    public List<PickingRegisterVO> queryList(PickingRegisterDTO pickingRegisterDTO){
        //排序字段名需要驼峰转数据库下划线类型字段名
        if(StringUtils.isNotEmpty(pickingRegisterDTO.getSortField())){
            pickingRegisterDTO.setSortField(CommonUtil.camel2Underline(pickingRegisterDTO.getSortField()));
        }
        List<PickingRegisterVO> pickingRegisterVOList = baseMapper.queryList(pickingRegisterDTO);
        return pickingRegisterVOList;
    }

    /**
     * 查询合计,包含总数
     * @param pickingRegisterDTO
     * @return
     */
    @Override
    public PickingRegisterVO queryListSum(PickingRegisterDTO pickingRegisterDTO){
        PickingRegisterVO pickingRegisterVO = baseMapper.queryListSum(pickingRegisterDTO);
        return pickingRegisterVO;
    }

    /**
     * @description PDA查询已拣货商品的详情列表
     * @param registerDTO :
     * @author xuyang
     * @date 2020/10/24 11:03
     **/
    @Override
    public List<PickingRegisterVO> queryRegisterList(PickingRegisterDTO registerDTO) {
        String groupCode = UserUtil.getBranchCode();
        registerDTO.setGroupCode(groupCode);
        String goodsCode = "";
        String goodsBarCode = registerDTO.getGoodsBarCode();
        String pickingCode = registerDTO.getPickingCode();
        if(StrUtil.isNotBlank(goodsBarCode)){
            String shipmentCode = pickingItemService.getShipmentCodeByPickingCode(pickingCode,groupCode);
            if(StrUtil.isNotBlank(shipmentCode)) {
                goodsCode = goodsPnService.getGoodsCode(shipmentCode,goodsBarCode);
            }
        }
        if (StrUtil.isNotEmpty(goodsCode)) {
            registerDTO.setGoodsCode(goodsCode);
            registerDTO.setGoodsBarCode(StrUtil.EMPTY);
        }
        List<PickingRegisterVO> registerVOS = this.queryList(registerDTO);
        /*if (IterUtil.isEmpty(registerVOS)){
            throw new ServiceException("查询结果为空");
        }*/
        // 添加批次规则
        if (IterUtil.isNotEmpty(registerVOS)) {
            registerVOS.stream().forEach(item -> {
                Map<String, Object> goodsCacheMap = goodsCache.get(item.getGoodsCode());
                Map<String, Object> batchRuleMap = batchRuleCache.get((String) goodsCacheMap.get(LOT_NUMBER));
                item.setBatchRule(batchRuleMap);
            });
        }
        return registerVOS;
    }

    /**
     * @param pickingRegister :
     * @description 保存，如果存在相同批次的数据，则在老数据上增加
     * @author xuyang
     * @date 2020/10/27 13:49
     **/
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Result distinctSave(PickingRegister pickingRegister) {
        // 查询是否有相同的数据，如果有则在原基础上增加数量，依据：拣货单明细、容器号、状态
        PickingRegister sameOne = this.getOne(new QueryWrapper<PickingRegister>().lambda()
                .eq(PickingRegister::getPickingItemCode, pickingRegister.getPickingItemCode())
                .eq(PickingRegister::getContainerBarCode, pickingRegister.getContainerBarCode())
                .eq(PickingRegister::getStatus, PickingRegisterStatusEnum.FINISH_PICKING.getValue()));
        if(sameOne != null){
            this.update(new UpdateWrapper<PickingRegister>().lambda().eq(PickingRegister::getCode, sameOne.getCode())
                        .setSql(" picking_quantity = picking_quantity + " + pickingRegister.getPickingQuantity())
                        .setSql(" not_picking_quantity = not_picking_quantity - " + pickingRegister.getPickingQuantity()));
        }else {
            pickingRegister.setCode(StrUtil.EMPTY);
            pickingRegister.setCreatedBy(StrUtil.EMPTY);
            pickingRegister.setModifiedBy(StrUtil.EMPTY);
            pickingRegister.setModifiedName(StrUtil.EMPTY);
            pickingRegister.setStatus(PickingRegisterStatusEnum.FINISH_PICKING.getValue());
            pickingRegister.setOperatorBy(UserUtil.getCode());
            pickingRegister.setNotPickingQuantity(BigDecimal.ZERO);
            pickingRegister.setOperatorName(partyCache.translate(UserUtil.getCode()));
            save(pickingRegister);
        }

        return Result.ok();
    }

    /**
     * 批量更新拣货登记取消数量
     *
     *
     * @param pickItemCancelQuantityDtoList@author liuxr
     * @date 2021/5/17 21:00
     */
    @Override
    public void updateCancelQuantityBatch(List<PickItemCancelQuantityDto> pickItemCancelQuantityDtoList) {
        this.baseMapper.updateCancelQuantityBatch(pickItemCancelQuantityDtoList);
    }

    /**
     * 获取拣货确认列表
     * @author rfwang
     * @date 2022/1/21 14:42
     * @param registerDTO
     * @return
     */
    @Override
    public Map<String,Object> pickingRegisterList(PickingRegisterDTO registerDTO){
        String groupCode = UserUtil.getBranchCode();
        Map<String, Object> resultMap = Maps.newHashMap();
        String taskCode = registerDTO.getTaskCode();
        //获取所有的拣货明细信息
        List<PdaPickingRegisterVO> totalRegisterVOS;
        //获取待拣货的拣货明细信息
        List<PdaPickingRegisterVO> registerVOS;
        DeliveryDistributionDTO deliveryDistributionDTO = new DeliveryDistributionDTO();
        deliveryDistributionDTO.setGroupCode(UserUtil.getBranchCode());
        if (StrUtil.isEmpty(taskCode)) {
            throw new ServiceException("任务单号不能为空");
        }
        WmsTask wmsTask = wmsTaskService.getOne(new LambdaQueryWrapper<WmsTask>()
                .eq(WmsTask::getCode, taskCode)
                .eq(WmsTask::getGroupCode,groupCode)
        );
        if (null == wmsTask) {
            throw new ServiceException("根据任务单号【" + taskCode + "】查询任务信息为空");
        }
        String pickingCode = wmsTask.getSourceCode();
        registerDTO.setPickingCode(pickingCode);
        registerDTO.setGroupCode(groupCode);
        totalRegisterVOS = this.pickingItemService.pickingItemList(registerDTO);
        if (IterUtil.isEmpty(totalRegisterVOS)) {
            throw new ServiceException("任务号【" + taskCode + "】没有拣货登记信息");
        }
        registerVOS = totalRegisterVOS.stream().filter(register -> StrUtil.equalsAny(register.getStatus(),PickingStatusEnum.NOT_PICK.getValue(),PickingStatusEnum.PICKING.getValue()))
                .collect(Collectors.toList());
        if (IterUtil.isEmpty(registerVOS)) {
            throw new ServiceException("任务号【" + taskCode + "】没有待拣货登记信息");
        }
        deliveryDistributionDTO.setWavePickingCode(registerVOS.get(NumConst.NUM_ZERO).getWavePickingCode());
        //1.获取拣货单确认集合
        if (StrUtil.isNotEmpty(registerDTO.getLocation()) && StrUtil.isNotEmpty(registerDTO.getGoodCode())) {
            deliveryDistributionDTO.setLocation(registerDTO.getLocation());
            deliveryDistributionDTO.setGoodCode(registerDTO.getGoodCode());
        } else {
            List<String> locations = registerVOS.stream().map(PdaPickingRegisterVO::getLocation).collect(Collectors.toList());
            deliveryDistributionDTO.setLocations(locations);
        }

        //2.获取订单顺序及数量集合
        int goodsSortQuantity = totalRegisterVOS.size();
        int pickedGoodsSortQuantity = goodsSortQuantity - registerVOS.size();
        deliveryDistributionDTO.setPageSize(NumConst.NUM_NINETY_NINE_THOUSAND_NINE_HUNDRED_NINETY_NINE);
        List<DeliveryDistributionVO> deliveryDistributionVOList = deliveryDistributionService.queryList(deliveryDistributionDTO);
        //按照库位加商品进行分组
        Map<String,List<DeliveryDistributionVO>> listMap = deliveryDistributionVOList.stream().collect(Collectors.groupingBy(e -> e.getLocation() + "_" + e.getGoodCode()));
        //3.组合1和2返回最终的结果，并按照库位编码排序
        registerVOS.stream().forEach(e -> {
            e.setDeliveryDistributionVOS(MapUtil.get(listMap, e.getLocation() + "_" + e.getGoodCode(), List.class));
            e.setLocationName(locationCache.translate(e.getLocation()));
            //更新待拣货数量
            e.setTotalQuantity(e.getTotalQuantity().subtract(e.getPickingQuantity()));
        });
        registerVOS = registerVOS.stream().sorted(Comparator.comparing(PdaPickingRegisterVO::getLocationName)).collect(Collectors.toList());
        //已拣货商品种数
        resultMap.put("pickedGoodsSortQuantity",pickedGoodsSortQuantity);
        //总的商品总数
        resultMap.put("goodsSortQuantity",goodsSortQuantity);
        resultMap.put("registerVOS", registerVOS);
        return resultMap;
    }

    /**
     * 查询拣货详情
     * @author rfwang
     * @date 2022/1/22 10:02
     * @param registerDTO
     * @return
     */
    @Override
    public Map<String, Object> pickingDetails(PickingRegisterDTO registerDTO){
        String groupCode = UserUtil.getBranchCode();
        Map<String, Object> map = Maps.newHashMap();
        String taskCode = registerDTO.getTaskCode();
        String status = registerDTO.getStatus();
        String pn = registerDTO.getPn();
        List<PdaPickingRegisterVO> registerVOS;
        DeliveryDistributionDTO deliveryDistributionDTO = new DeliveryDistributionDTO();
        //1.获取拣货单确认集合
        if (StrUtil.isEmpty(taskCode)) {
            throw new ServiceException("任务单号不能为空");
        }
        WmsTask wmsTask = wmsTaskService.getOne(new LambdaQueryWrapper<WmsTask>()
                .eq(WmsTask::getCode, taskCode)
                .eq(WmsTask::getGroupCode,groupCode)
        );
        if (null == wmsTask) {
            throw new ServiceException("根据任务单号【" + taskCode + "】查询任务信息为空");
        }
        String pickingCode = wmsTask.getSourceCode();
        registerDTO.setPickingCode(pickingCode);
        //查询所有状态的，然后进行过滤
        registerDTO.setStatus(StrUtil.EMPTY);
        registerDTO.setGroupCode(groupCode);
        registerVOS =  this.pickingItemService.pickingItemList(registerDTO);
        if (IterUtil.isEmpty(registerVOS)) {
            throw new ServiceException("拣货单号【" + pickingCode + "】没有拣货登记信息");
        }



        //2.汇总数据
        Set<String> goodsSet = registerVOS.stream().map(PdaPickingRegisterVO::getGoodsCode).collect(Collectors.toSet());
        BigDecimal pickingQuantity = registerVOS.stream().map(PdaPickingRegisterVO::getPickingQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalQuantity = registerVOS.stream().map(PdaPickingRegisterVO::getTotalQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        Set<String> totalLocationsSet = registerVOS.stream().map(PdaPickingRegisterVO::getLocation).collect(Collectors.toSet());
        int goodsSortQuantity = goodsSet.size();

        //3.获取订单顺序及数量集合
        //根据状态获取最终返回的结果
        List<PdaPickingRegisterVO> pdaPickingRegisterVOS = Lists.newArrayList();
        //pda如果是待拣货状态，查询的时候包含待检货和拣货中两种状态
        if (PickingStatusEnum.NOT_PICK.getValue().equals(status)) {
            pdaPickingRegisterVOS = registerVOS.stream().filter(register -> StrUtil.equalsAny(register.getStatus(),PickingStatusEnum.NOT_PICK.getValue(),PickingStatusEnum.PICKING.getValue()))
                    .collect(Collectors.toList());
        }
        if (PickingStatusEnum.FINISH_PICK.getValue().equals(status)) {
            pdaPickingRegisterVOS = registerVOS.stream().filter(register -> status.equals(register.getStatus())).collect(Collectors.toList());
        }

        //根据pn码进行筛选时，进行再次过滤
        if (StrUtil.isNotEmpty(pn)) {
            String shipmentCode = pickingItemService.getShipmentCodeByPickingCode(pickingCode,groupCode);
            String goodsCode = goodsPnService.getGoodsCode(shipmentCode, pn);
            Goods goods = goodsCache.getObj(goodsCode);
            if (null == goods) {
                throw new ServiceException("没有查到商品pn码为【" + pn + "】的商品信息");
            }
            pdaPickingRegisterVOS = pdaPickingRegisterVOS.stream().filter(register -> register.getGoodCode().equals(goods.getGoodCode())).collect(Collectors.toList());
        }


        if (IterUtil.isNotEmpty(pdaPickingRegisterVOS)) {
            Set<String> locationsSet = pdaPickingRegisterVOS.stream().map(PdaPickingRegisterVO::getLocation).collect(Collectors.toSet());
            List<String> locations = new ArrayList<>(locationsSet);
            String wavePickingCode = registerVOS.get(NumConst.NUM_ZERO).getWavePickingCode();
            deliveryDistributionDTO.setWavePickingCode(wavePickingCode);
            deliveryDistributionDTO.setLocations(locations);
            deliveryDistributionDTO.setPageSize(NumConst.NUM_NINETY_NINE_THOUSAND_NINE_HUNDRED_NINETY_NINE);
            List<DeliveryDistributionVO> deliveryDistributionVOList = deliveryDistributionService.queryList(deliveryDistributionDTO);
            Map<String,List<DeliveryDistributionVO>> listMap = deliveryDistributionVOList.stream().collect(Collectors.groupingBy(e -> e.getLocation() + "_" + e.getGoodCode()));

            //3.组合1和2返回最终的结果，并按照库位编码排序
            pdaPickingRegisterVOS.stream().forEach(e -> {
                e.setDeliveryDistributionVOS(MapUtil.get(listMap,e.getLocation() + "_" + e.getGoodCode(),List.class));
                e.setLocationName(locationCache.translate(e.getLocation()));
                e.setTotalQuantity(e.getTotalQuantity().subtract(e.getPickingQuantity()));
            });
            pdaPickingRegisterVOS = pdaPickingRegisterVOS.stream().sorted(Comparator.comparing(PdaPickingRegisterVO::getLocationName)).collect(Collectors.toList());
        }

        map.put("taskCode",taskCode);
        map.put("locationNum", totalLocationsSet.size());
        map.put("goodsSortQuantity",goodsSortQuantity);
        map.put("pickingQuantity", pickingQuantity);
        map.put("totalQuantity",totalQuantity);
        map.put("registerVOS", pdaPickingRegisterVOS);
        return map;
    }


}
